;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Import the classes to be used ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(import org.parademo.model.*)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Template declarations for the respective classes ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(deftemplate Community (declare (from-class CommunityEntity)))
(deftemplate Member (declare (from-class MemberEntity)))
(deftemplate Proposal (declare (from-class ProposalEntity)))
(deftemplate Region (declare (from-class RegionEntity)))
(deftemplate TokenCredit (declare (from-class TokenCreditEntity)))
(deftemplate Vote (declare (from-class VoteEntity)))

;; A sample template that is used to trigger an undefrule ;;
(deftemplate triggerUndefRule (slot one))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Set watches if necessary ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;(watch facts)
;;(watch rules)
;;(watch activations)
;;(watch all)

;;;;;;;;;;;;;;;;
;; DefGlobals ;;
;;;;;;;;;;;;;;;;

(
    defglobal ?*participation-percentage* = 0.75
    ?*trigger-rule-change* = false
)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; reset and other initial calls ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(reset)

;;(ppdeftemplate Community)
;;(ppdeftemplate Member)
;;(ppdeftemplate Vote)
;;(ppdeftemplate Proposal)
;;(ppdeftemplate Region)
;;(ppdeftemplate TokenCredit)

;;;;;;;;;;;;;;;;;;;;;;
;; Rule Definitions ;;
;;;;;;;;;;;;;;;;;;;;;;

;; A Rule to announce proposals ;;
(defrule rule0-announce-proposals
	"Rule0 - A rule that announces proposals upon their creation"
    (declare (salience -100))
	(Proposal (title ?title ) (description ?desc))
	=>
	(printout t "A new proposal has been asserted with title=" (?title toString) " and desc=" (?desc toString) crlf)
	;(printout t (agenda *) crlf)
)

;; A dummy Rule to be deleted ;;
(defrule rule0A-to-undef
	"Rule0A - A rule is will be deleted during testing"
	(declare (salience -101))
	(Proposal (title ?title ) (description ?desc))
	=>
)

;; Rule to handle Proposals that change of constitution ;;
(defrule rule01-approval-proposal-for-constitution-change
 "Rule1 - Check if the given proposal has a title and description and if the category is marked Internal"
 (declare (salience 20))
 ?proposal <- (Proposal
    (title ?title&: (neq ?title nil))
    (description ?desc&: (neq description nil))
   ;(category ?category&: (eq (?category toString) =(Category.Internal.name) ))
 )
 =>
 (printout t "This internal proposal can be accepted!" crlf)
)

;; Rule verify that atleast 75% of the community has shown participation for a given proposal ;;
(defrule rule02-percentage-showing-participation
"Rule2 - Check if the proposal has finished its voting period and check if the % of voters is atleast 75%"

    (declare (salience 9))
    ?proposal <- (Proposal)

        (bind ?author ?proposal.author)
        (bind ?community ?author.community)
        (bind ?members ?community.members)
        (bind ?memberStrength =(?members size) )

        (bind ?votes ?proposal.votes)
        (bind ?numberOfVoters =(?votes size) )

        (bind ?percentage =(/ ?numberOfVoters ?memberStrength))
        ;(test (>= ?percentage ?*participation-percentage*))
        (test (eq ?percentage 1))
    =>
    (printout t "Member Strength of the community: " ?memberStrength crlf)
    (printout t "Percentage of voting users: " ?percentage crlf)
    (printout t "The proposal " ?proposal.title " can be accepted as it meets the requirements of a 75% member participation" crlf)
)

;; Rule to delete an existing rule ;;
(defrule rule03-delete-an-existing-rule
"Delete the dummy rule if a sample template is found as expected"
(triggerUndefRule (one 10))
=>
(undefrule rule0A-to-delete)
(printout t "The rule rule0A-to-delete has been undefruled!" crlf)
)

;; Rule to change the 75% participation rule ;;
(defrule rule04-change-75-participation-rule
"Change the 75% community member participation rule"
    ;(category ?category&: (eq (?category toString) (Category.Internal.name) ))
    (eq TRUE ?*trigger-rule-change*)
=>
    (printout t "The 75% member participation rule has not changed!" crlf)
)

;;;;;;;;;;;;;;;;
;; NEXT STEPS ;;
;;;;;;;;;;;;;;;;
;; Create a pseudo-code for the rules that are fired for every test-case from section 4.2.4.
;; Start implementing each processes/rules from the LHS from each rule.
;; Implement the actions present in the RHS for each rule (and the triggering of other rules if necessary).
;; Assert the necessary set of facts for each test-case to be verified.

;; Rule to trigger changes in the working memory for a vote - pseudo code ;;
(defrule rule05-update-vote-on-proposal
"A rule that triggers the processes for updating the vote on a proposal"
(Check_if_proposal_is_valid)
(count_user_votes ?proposal ?user)
=>
(Calculate_update_weighted_average_for_proposal_with_user_tokens)
(Update_the_voter_list_for_proposal)
(ppdefrule MAIN::rule02-percentage-showing-participation)
)

;; Rule to withdraw a user vote - pseudo code ;;
(defrule rule06-withdraw-user-vote
"A rule that will withdraw a member's vote cast"
(return_member_vote ?proposal ?user)
=>
(printout t "Member " ?user.name " has had his/her vote withdrawn" crlf)
)

;; Rule to withdraw a user vote - pseudo code ;;
(defrule rule07-recast-user-vote
"A rule that will allow a member to re-cast a vote"
(check-member-has-not-already-recast)
=>
(Calculate_update_weighted_average_for_proposal_with_new_user_tokens)
(Update_the_voter_list_for_proposal)
(printout t "Member " ?user.name " has cast another vote again" crlf)
)

;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Function definitions ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;

(deffunction count_user_votes (?proposal ?user)
    if (Member_has_the_required_number_of_votes) then
        (return true)
    else
        (return false)
)

(deffunction return_member_vote (?proposal ?user)
    return ?user.tokens
)